//
// Created by haoy on 2017/4/29.
//

#ifndef RTC_XSWITCH2_HTTP_HPP
#define RTC_XSWITCH2_HTTP_HPP

#include <functional>
#include <libsoup/soup.h>
#include <xm_log.h>

/// HttpCallback wraps a callable into libsoup's callback userdata
class HttpCallback {
public:
    HttpCallback(std::function<void(int, const std::string&)>&& callback) : _callback(callback) {}
    void operator()(int status_code, const std::string& message) { _callback(status_code, message); }
private:
    std::function<void(int, const std::string&)> _callback;
};

void post_complete_callback(SoupSession *session, SoupMessage *msg, gpointer user_data);

class HttpClient {
public:
    HttpClient() {}

    virtual ~HttpClient() {
        if (_soup_session) {
            soup_session_abort(_soup_session);
            g_object_unref(_soup_session); _soup_session = nullptr;
        }
    }

    bool init(GMainContext* gctx) {
        // todo: figure out why
        // at a higher connection speed, e.g. 100 conn per second, soup_session_new_with_options will panic
        _soup_session = soup_session_new_with_options(SOUP_SESSION_TIMEOUT, 3,
                                                      SOUP_SESSION_MAX_CONNS, 1000,
                                                      SOUP_SESSION_MAX_CONNS_PER_HOST, 1000,
                                                      SOUP_SESSION_IDLE_TIMEOUT, 3,
                                                      nullptr);
        auto main_ctx = soup_session_get_async_context(_soup_session);

        // uncomment to get some http logs
//        auto logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, -1);
//        soup_session_add_feature (_soup_session, SOUP_SESSION_FEATURE (logger));
//        g_object_unref (logger);

        if (!_soup_session) { return false; }

        return true;
    }

    // note: After callback is fired, it will be deleted by post_complete_callback, you need to new HttpCallback for every call
    bool async_post(const std::string& uri, const std::string& content_type,
            const std::string& body, HttpCallback* callback) {
        dbgd("POST %s\n%s", uri.c_str(), body.c_str());
        SoupMessage* msg = soup_message_new("POST", uri.c_str());
        soup_message_set_http_version(msg, SOUP_HTTP_1_1);
        soup_message_set_request(msg, content_type.c_str(), SOUP_MEMORY_COPY, body.c_str(), body.length());
        soup_session_queue_message(_soup_session, msg, post_complete_callback, callback);
        return true;
    }

    bool async_get(const std::string& uri, HttpCallback* callback) {
        dbgd("GET %s\n", uri.c_str());
        SoupMessage* msg = soup_message_new("GET", uri.c_str());
        soup_message_set_http_version(msg, SOUP_HTTP_1_1);
        soup_session_queue_message(_soup_session, msg, post_complete_callback, callback);
        return true;
    }
private:
    SoupSession* _soup_session;
};



#endif //RTC_XSWITCH2_HTTP_HPP
